/*
 * newList_test.cpp
 *
 *  Created on: 21/06/2011
 *      Author: Yotam and Gilaad
 */

#include <assert.h>
#include "../mtm.h"
#include "../list.h"
#include <stdarg.h>
#include "mtmtest.h"
#include <iostream>
using namespace std;


class IntEquals {
	int i;
public:
	IntEquals(int i) : i(i) {}
	bool operator()(const int& x) const
	{
		return x == i;
	}
};

class IntCompare {
public:
	bool operator()(const int& i1, const int& i2) const
	{
		return i1 < i2;
	}
};

bool testCreate() {
    List<int> newList;
    ASSERT_EQUALS(0, newList.getSize());
    Iterator<int> iterator1 = newList.begin();
    ASSERT_EQUALS(iterator1,newList.end());
    ASSERT_NO_THROW(newList.insert(1,iterator1));
    ASSERT_EQUALS(1, newList.getSize());
    List<int> copy(newList);
    ASSERT_EQUALS(1, copy.getSize());
    Iterator<int> iterator2 = copy.begin();
    ASSERT_EQUALS(1,*iterator2);
    ASSERT_NO_THROW(copy.insert(1, iterator2));
    ASSERT_EQUALS(2, copy.getSize());
    ASSERT_EQUALS(1, newList.getSize());
    Iterator<int> iterator3(newList.begin());
    ASSERT_EQUALS(iterator3, newList.begin());
    ASSERT_EQUALS(*iterator3,1);
    Iterator<int> iterator4 = newList.end();
    ASSERT_EQUALS(iterator4,newList.end());

    return true;
}
bool testDestroyList() {
	// checked in valgrind
	return true;
}
bool testBeginEnd() {
    List<int> newList;
    Iterator<int> iterator1 = newList.begin();
    ASSERT_THROW(ListExceptions::ElementNotFound, *iterator1);
    ASSERT_EQUALS(iterator1,newList.end());
    ASSERT_NO_THROW(iterator1++);
    ASSERT_EQUALS(iterator1,newList.end());
    ASSERT_NO_THROW(newList.insert(5, newList.begin())); // 5
    ASSERT_NO_THROW(newList.insert(1, newList.begin())); // 1 5
    ASSERT_NO_THROW(newList.insert(7, newList.end())); // 1 5 7
    ASSERT_NO_THROW(newList.insert(4, newList.end())); // 1 5 7 4
    Iterator<int> iterator2 = newList.begin();
    ASSERT_EQUALS(1,*iterator2);
    ASSERT_EQUALS(5,*(++iterator2));
    ASSERT_EQUALS(5,*(iterator2++));
    ASSERT_EQUALS(7,*iterator2);
    ASSERT_NO_THROW(iterator2++);
    ASSERT_EQUALS(4,*(iterator2++));
    ASSERT_EQUALS(iterator2,newList.end());
    ASSERT_THROW(ListExceptions::ElementNotFound, *iterator2);

    return true;
}
bool testGetSize() {
	List<int> newList;
	ASSERT_EQUALS(0,newList.getSize());
    ASSERT_NO_THROW(newList.insert(1, newList.begin())); // 1
    ASSERT_EQUALS(1,newList.getSize());
    ASSERT_NO_THROW(newList.insert(2, newList.begin())); // 2 1
    ASSERT_EQUALS(2,newList.getSize());
    ASSERT_NO_THROW(newList.remove(newList.begin())); // 1
    ASSERT_EQUALS(1,newList.getSize());
    ASSERT_NO_THROW(newList.remove(newList.begin())); // empty
    ASSERT_EQUALS(0,newList.getSize());

    return true;
}
bool testInsert() {
    List<int> newList;
    ASSERT_NO_THROW(newList.insert(5, newList.begin())); // 5
    ASSERT_NO_THROW(newList.insert(6, newList.begin())); // 6 5
    ASSERT_NO_THROW(newList.insert(7, newList.end())); // 6 5 7
    ASSERT_NO_THROW(newList.insert(8, newList.end())); // 6 5 7 8
    Iterator<int> iterator = newList.begin();
    ASSERT_NO_THROW(iterator++);
    ASSERT_NO_THROW(iterator++);
    ASSERT_NO_THROW(newList.insert(9,iterator)); // 6 5 9 7 8
    ASSERT_NO_THROW(iterator = newList.begin());
    ASSERT_EQUALS(6,*(iterator++));
    ASSERT_EQUALS(5,*(iterator++));
    ASSERT_EQUALS(9,*(iterator++));
    ASSERT_EQUALS(7,*(iterator++));
    ASSERT_EQUALS(8,*(iterator++));
    List<int> copy(newList);
    iterator = newList.begin();
    Iterator<int> copyIterator = copy.begin();
    ASSERT_THROW(ListExceptions::ElementNotFound, copy.insert(5,iterator));
    ASSERT_THROW(ListExceptions::ElementNotFound, newList.insert(5,copyIterator));

    return true;
}
bool testRemove() {
    List<int> newList;
    Iterator<int> iterator = newList.end();
    ASSERT_THROW(ListExceptions::ElementNotFound, newList.remove(newList.begin()));
    ASSERT_THROW(ListExceptions::ElementNotFound, newList.remove(newList.end()));
    ASSERT_NO_THROW(newList.insert(5, newList.begin()));
    ASSERT_NO_THROW(newList.insert(4, newList.begin()));
    ASSERT_NO_THROW(newList.insert(3, newList.begin()));
    ASSERT_NO_THROW(newList.insert(2, newList.begin()));
    ASSERT_NO_THROW(newList.insert(1, newList.begin()));
    // newList 1 2 3 4 5
    List<int> copy(newList);
    Iterator<int> copyIterator = copy.begin();
    ASSERT_THROW(ListExceptions::ElementNotFound, newList.remove(copyIterator));
    ASSERT_THROW(ListExceptions::ElementNotFound, copy.remove(iterator));
    ASSERT_NO_THROW(newList.remove(newList.begin())); // 2 3 4 5
    ASSERT_EQUALS(4, newList.getSize());
    ASSERT_NO_THROW(iterator = newList.begin());
    ASSERT_NO_THROW(iterator++);
    ASSERT_NO_THROW(newList.remove(iterator)); // 2 4 5
    ASSERT_EQUALS(3, newList.getSize());
    //Clear newList
    ASSERT_NO_THROW(newList.remove(newList.begin())); // 4 5
    ASSERT_NO_THROW(newList.remove(newList.begin())); // 5
    ASSERT_NO_THROW(newList.remove(newList.begin())); // empty
    //List is empty
    ASSERT_EQUALS(0,newList.getSize());

    return true;
}
bool testSort() {
    List<int> newList;
    ASSERT_NO_THROW(newList.sort(IntCompare()));
    ASSERT_NO_THROW(newList.insert(1, newList.begin())); // 1
    ASSERT_NO_THROW(newList.sort(IntCompare()));
    ASSERT_EQUALS(1,newList.getSize());
    ASSERT_EQUALS(1,*newList.begin());
    ASSERT_NO_THROW(newList.insert(2, newList.begin())); // 2 1
    ASSERT_NO_THROW(newList.insert(3, newList.end())); // 2 1 3
    //Sort Ascending
    ASSERT_NO_THROW(newList.sort(IntCompare())); // 1 2 3
    Iterator<int> node = newList.begin();
    for(int counter=1; node != newList.end(); ++node, ++counter) {
    	ASSERT_EQUALS(counter,*node);
    }

    return true;
}
bool testFind() {
	List<int> newList;
    ASSERT_EQUALS(newList.find(IntEquals(30)),newList.end());
    ASSERT_NO_THROW(newList.insert(8,newList.begin()));
    ASSERT_NO_THROW(newList.insert(2,newList.begin()));
    ASSERT_NO_THROW(newList.insert(3,newList.begin()));
    ASSERT_NO_THROW(newList.insert(3,newList.begin()));
    ASSERT_NO_THROW(newList.insert(12,newList.begin()));
    ASSERT_EQUALS(newList.find(IntEquals(12)),newList.begin());
    Iterator<int> iterator = newList.begin();
    ASSERT_NO_THROW(iterator++);
    ASSERT_EQUALS(newList.find(IntEquals(3)),iterator);
    for(int i=0; i<3; i++){
    	 ASSERT_NO_THROW(iterator++);
    }
    ASSERT_EQUALS(newList.find(IntEquals(8)),iterator);

    return true;
}
bool testAccessOperator() {
	List<int> newList;
	ASSERT_NO_THROW(newList.insert(6,newList.end()));
	ASSERT_NO_THROW(newList.insert(5,newList.end()));
	ASSERT_NO_THROW(newList.insert(4,newList.end()));
	ASSERT_NO_THROW(newList.insert(3,newList.end()));
	ASSERT_THROW(ListExceptions::ElementNotFound, *(newList.end()));
	Iterator<int> iterator = newList.end();
	ASSERT_THROW(ListExceptions::ElementNotFound, *iterator);
	ASSERT_NO_THROW(iterator = newList.begin());
	ASSERT_EQUALS(*iterator,6);
	ASSERT_EQUALS(*(++iterator),5);
	ASSERT_EQUALS(*(++iterator),4);
	ASSERT_EQUALS(*(++iterator),3);

    return true;
}
bool testNextOperator1() {
	List<int> newList;
	ASSERT_NO_THROW(newList.insert(1,newList.end()));
	ASSERT_NO_THROW(newList.insert(2,newList.end()));
	ASSERT_NO_THROW(newList.insert(3,newList.end()));
	ASSERT_NO_THROW(newList.insert(4,newList.end()));
	ASSERT_NO_THROW(newList.insert(5,newList.end()));
	ASSERT_NO_THROW(newList.insert(6,newList.end()));
	ASSERT_NO_THROW(newList.insert(-10,newList.end()));
	// newList is now: 1 2 3 4 5 6 -10
	List<int> copy(newList);
	Iterator<int> iterator = newList.begin();
	Iterator<int> copyIterator = copy.begin();
	ASSERT_NO_THROW(iterator++);
	ASSERT_EQUALS(*iterator,2);
	ASSERT_EQUALS(copy.begin(),copyIterator++);
	ASSERT_EQUALS(*(copyIterator++),2);
	ASSERT_EQUALS(*(copyIterator++),3);
	ASSERT_EQUALS(*(iterator++),2);
	iterator = newList.end();
	ASSERT_EQUALS(newList.end(),iterator++);
	ASSERT_EQUALS(newList.end(),iterator);
	ASSERT_EQUALS(newList.end(),iterator++);
	copyIterator = copy.end();
	ASSERT_EQUALS(iterator == copyIterator, false);

    return true;
}
bool testNextOperator2() {
	List<int> newList;
	ASSERT_NO_THROW(newList.insert(1,newList.end()));
	ASSERT_NO_THROW(newList.insert(2,newList.end()));
	ASSERT_NO_THROW(newList.insert(3,newList.end()));
	ASSERT_NO_THROW(newList.insert(4,newList.end()));
	ASSERT_NO_THROW(newList.insert(5,newList.end()));
	ASSERT_NO_THROW(newList.insert(6,newList.end()));
	ASSERT_NO_THROW(newList.insert(-10,newList.end()));
	// newList is now: 1 2 3 4 5 6 -10
	List<int> copy(newList);
	Iterator<int> iterator = newList.begin();
	Iterator<int> copyIterator = copy.begin();
	ASSERT_NO_THROW(++iterator);
	ASSERT_EQUALS(copyIterator,copy.begin());
	ASSERT_EQUALS(*(++copyIterator),2);
	ASSERT_EQUALS(3,*(++copyIterator));
	iterator = newList.end();
	ASSERT_EQUALS(newList.end(),++iterator);
	ASSERT_EQUALS(++iterator,newList.end());
	ASSERT_EQUALS(++iterator,newList.end());
	ASSERT_EQUALS(newList.end(),++iterator);

	return true;
}
bool testCompareOperators() {
	List<int> newList;
	ASSERT_NO_THROW(newList.insert(1,newList.end()));
	ASSERT_NO_THROW(newList.insert(2,newList.end()));
	ASSERT_NO_THROW(newList.insert(3,newList.end()));
	ASSERT_NO_THROW(newList.insert(4,newList.end()));
	ASSERT_NO_THROW(newList.insert(5,newList.end()));
	ASSERT_NO_THROW(newList.insert(6,newList.end()));
	ASSERT_NO_THROW(newList.insert(-10,newList.end()));
	// newList is now: 1 2 3 4 5 6 -10
	List<int> copy(newList);
	Iterator<int> iterator = newList.begin();
	Iterator<int> copyIterator = copy.begin();
	ASSERT_EQUALS(iterator == newList.begin(), true);
	ASSERT_EQUALS(copyIterator == copy.begin(), true);
	ASSERT_EQUALS(*iterator == *copyIterator, true);
	ASSERT_EQUALS(iterator != copyIterator, true);
	for( int i=0; i<7 ;i++ ){
		ASSERT_NO_THROW(iterator++);
	}
	ASSERT_EQUALS(iterator == newList.end(), true);
	ASSERT_EQUALS(copyIterator != copy.end(), true);

    return true;
}

int main(){
	RUN_TEST(testCreate);
	RUN_TEST(testDestroyList);
	RUN_TEST(testBeginEnd);
	RUN_TEST(testGetSize);
	RUN_TEST(testInsert);
	RUN_TEST(testRemove);
	RUN_TEST(testSort);
	RUN_TEST(testFind);
	RUN_TEST(testAccessOperator);
	RUN_TEST(testNextOperator1); //operator()++
	RUN_TEST(testNextOperator2); //operator++()
	RUN_TEST(testCompareOperators);

return 0;
}
